package de.softwareforge.published.util;

/*
 * Copyright (C) 2007-2008 Henning P. Schmiedehausen
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import com.sun.javadoc.Doc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.RootDoc;
import com.sun.javadoc.Tag;

import static de.softwareforge.published.util.LocaleMsg.WARN_NO_LEVEL;
import static de.softwareforge.published.util.LocaleMsg.WARN_NO_TAGEXT;
import static de.softwareforge.published.util.LocaleMsg.WARN_TOO_MANY_TAGS;
import static de.softwareforge.published.util.LocaleMsg.WARN_UNKNOWN_LEVEL;
import static de.softwareforge.published.util.LocaleMsg.WARN_UNKNOWN_STATE;

/**
 * Various helpers for the Publishing Doclet and Taglet.
 *
 * @author <a href="mailto:henning@schmiedehausen.org">Henning P. Schmiedehausen</a>
 * @version $Id:Utils.java 357 2007-08-13 20:57:20Z hps@intermeta.de $
 * @api.level unpublished
 */
public final class Utils
{

    /**
     * Creates a new Utils object.
     */
    private Utils()
    { }

    private static final PublishInformation[][] PUBLISH_INFORMATION =
        new PublishInformation[][]
        {
            new PublishInformation[] { PublishInformation.UNPUBLISHED, },
            new PublishInformation[]
            {
                PublishInformation.UNSTABLE,
                PublishInformation.REVISION,
                PublishInformation.MINOR,
                PublishInformation.MAJOR,
                PublishInformation.PUBLISHED,
            },
        };

    /**
     * Process the given tags to find the first api.level tag.
     *
     * @param tags An array of Tags. Might be empty or null.
     * @param messages A {@link Locale} object for displaying messages.
     *
     * @return A String array of fields from the tag or null if no tag was found.
     */
    public static String[] processTags(final Tag[] tags, final Locale messages)
    {

        if ((tags == null) || (tags.length == 0))
        {
            return null;
        }

        String name = tags[0].holder().name();

        if (tags.length > 1)
        {
            messages.warn(WARN_TOO_MANY_TAGS, name);
        }

        return parseOption(tags[0].text(), name, messages);
    }

    /**
     * Split a given text into multiple fields.
     *
     * @param text The text to split.
     * @param name Name of the location where the text was found (for messages).
     * @param messages A {@link Locale} object for displaying messages.
     *
     * @return A String array of fields from the tag or null if the String could not be split.
     */
    public static String[] parseOption(final String text, final String name, final Locale messages)
    {

        if ((text == null) || (text.length() == 0))
        {
            messages.warn(WARN_NO_TAGEXT, name);

            return null;
        }

        String[] fields = text.split("[\\s_]+", 2);

        for (int i = 0; i < fields.length; i++)
        {

            if (fields[i] != null)
            {
                fields[i] = fields[i].trim();
            }
        }

        return fields;
    }

    /**
     * Find a {@link PublishInformation} object representing the publish status and level given in the fields.
     *
     * @param fields An array of Strings containing one or more Strings representing a publishing level as String. Must not be null
     *               or empty.
     * @param name Name of the location where the text was found (normally the place where a tag was present). Needed for messages.
     * @param messages A {@link Locale} object for displaying messages.
     *
     * @return A {@link PublishInformation} object representing the publish status and level or null if no suitable object was
     *         found.
     */
    public static PublishInformation getPublishInformation(final String[] fields, final String name, final Locale messages)
    {

        for (int i = 0; i < PUBLISH_INFORMATION.length; i++)
        {

            if (PUBLISH_INFORMATION[i][0].getPublished().equalsIgnoreCase(fields[0]))
            {

                if (PUBLISH_INFORMATION[i][0].getLevel() == null)
                {
                    return PUBLISH_INFORMATION[i][0];
                }

                if (fields.length < 2)
                {
                    messages.warn(WARN_NO_LEVEL, name);

                    return null;
                }

                for (int j = 0; j < PUBLISH_INFORMATION[i].length; j++)
                {

                    if (PUBLISH_INFORMATION[i][j].getLevel().equalsIgnoreCase(fields[1]))
                    {
                        return PUBLISH_INFORMATION[i][j];
                    }
                }

                messages.warn(WARN_UNKNOWN_LEVEL, name, fields[1]);

                return null;
            }
        }

        messages.warn(WARN_UNKNOWN_STATE, name, fields[0]);

        return null;
    }

    /**
     * Return a locale lookup key depending on the document type.
     *
     * @param doc A {@link Doc} object. Must not be null.
     *
     * @return A locale lookup key. Is never null but can be <code>unknown</code> if no suitable type was found.
     */
    public static String findHolderType(final Doc doc)
    {
        if (doc.isAnnotationType())
        {
            return "annotationType";
        }

        if (doc.isAnnotationTypeElement())
        {
            return "annotationTypeElement";
        }

        if (doc.isEnum())
        {
            return "enum";
        }

        if (doc.isEnumConstant())
        {
            return "enumConstant";
        }

        if (doc.isInterface())
        {
            return "interface";
        }

        if (doc.isMethod())
        {
            return "method";
        }

        if (doc.isConstructor())
        {
            return "constructor";
        }

        if (doc.isField())
        {
            return "field";
        }

        if (doc.isClass())
        {
            return "class";
        }

        if (doc instanceof PackageDoc)
        {
            return "package";
        }

        if (doc instanceof RootDoc)
        {
            return "root";
        }

        return "unknown";
    }
}
